#include <iostream>
#include <print>
#include <string>

/*
 * 2024/3/26
 * Compilation principle
 * Lexical Analyzer
 * Author: 甘劲博
 * StudentID: 2110551202
 * Class: 21计科5
 *
 */
inline bool isDigital(const char &c) {
    if (c >= '0' && c <= '9')
        return true;
    else
        return false;
}

inline bool isLowCaseLetter(const char &c) {
    if (c >= 'a' && c <= 'z')
        return true;
    else
        return false;
}

inline bool isUpperCaseLetter(const char &c) {
    if (c >= 'A' && c <= 'Z')
        return true;
    else
        return false;
}

inline bool isAdd(const char &c) {
    return c == '+';
}

inline bool isReduce(const char &c) {
    return c == '-';
}

inline bool isMultiply(const char &c) {
    return c == '*';
}

inline bool isDivision(const char &c) {
    return c == '/';
}

inline bool isColon(const char &c) {
    return c == ':';
}

inline bool isLessThan(const char &c) {
    return c == '<';
}

inline bool isGreaterThan(const char &c) {
    return c == '>';
}

inline bool isEqual(const char &c) {
    return c == '=';
}

inline bool isSemicolon(const char &c) {
    return c == ';';
}

inline bool isOpenParenthesis(const char &c) {
    return c == '(';
}

inline bool isCloseParenthesis(const char &c) {
    return c == ')';
}

inline bool isHash(const char &c) {
    return c == '#';
}

inline bool isNull(const char &c) {
    return c == ' ';
}

void scanner(const std::string &s) {
    std::string buf{};
    for (int i = 0; i < s.size(); i++) {
        if (isNull(s[i])) {
            buf = {};
            continue;
        }
        if (isAdd(s[i])) {
            std::print("({},{}) ", 13, "+");
            continue;
        }
        if (isReduce(s[i])) {
            std::print("({},{}) ", 14, "-");
            continue;
        }
        if (isMultiply(s[i])) {
            std::print("({},{}) ", 15, "*");
            continue;
        }
        if (isDivision(s[i])) {
            std::print("({},{}) ", 16, "/");
            continue;
        }
        if (isColon(s[i]) && isEqual(s[i + 1])) {
            std::print("({},{}) ", 18, ":=");
            i++;
            continue;
        }
        if (isColon(s[i])) {
            std::print("({},{}) ", 17, ":");
            continue;
        }
        if (isLessThan(s[i]) && isGreaterThan(s[i + 1])) {
            std::print("({},{}) ", 21, "<>");
            i++;
            continue;
        }
        if (isLessThan(s[i]) && isEqual(s[i + 1])) {
            std::print("({},{}) ", 22, "<=");
            i++;
            continue;
        }
        if (isGreaterThan(s[i]) && isEqual(s[i + 1])) {
            std::print("({},{}) ", 24, ">=");
            i++;
            continue;
        }
        if (isLessThan(s[i])) {
            std::print("({},{}) ", 20, "<");
            continue;
        }
        if (isGreaterThan(s[i])) {
            std::print("({},{}) ", 23, ">");
            continue;
        }
        if (isEqual(s[i])) {
            std::print("({},{}) ", 25, "=");
            continue;
        }
        if (isSemicolon(s[i])) {
            std::print("({},{}) ", 26, ";");
            continue;
        }
        if (isOpenParenthesis(s[i])) {
            std::print("({},{}) ", 27, "(");
            continue;
        }
        if (isCloseParenthesis(s[i])) {
            std::print("({},{}) ", 28, ")");
            continue;
        }
        if (isHash(s[i])) {
            std::print("({},{}) ", 29, "#");
            continue;
        }
        if (i + 5 < s.size() && std::string(s.begin() + i, s.begin() + i + 5) == "begin") {
            std::print("({},{}) ", 1, "begin");
            i += 4;
            continue;
        }
        if (i + 2 < s.size() && std::string(s.begin() + i, s.begin() + i + 2) == "if") {
            std::print("({},{}) ", 2, "if");
            i += 1;
            continue;
        }
        if (i + 4 < s.size() && std::string(s.begin() + i, s.begin() + i + 4) == "then") {
            std::print("({},{}) ", 3, "then");
            i += 3;
            continue;
        }
        if (i + 5 < s.size() && std::string(s.begin() + i, s.begin() + i + 5) == "while") {
            std::print("({},{}) ", 4, "while");
            i += 4;
            continue;
        }
        if (i + 2 < s.size() && std::string(s.begin() + i, s.begin() + i + 2) == "do") {
            std::print("({},{}) ", 5, "do");
            i += 1;
            continue;
        }
        if (i + 3 < s.size() && std::string(s.begin() + i, s.begin() + i + 3) == "end") {
            std::print("({},{}) ", 6, "end");
            i += 2;
            continue;
        }
        if (isDigital(s[i]) && buf == "") {
            while (isDigital(s[i])) {
                buf += s[i];
                i++;
            }
            std::print("({},{}) ", 11, buf);
            buf = {};
            i -= 1;
            continue;
        }
        if (isLowCaseLetter(s[i]) || isUpperCaseLetter(s[i])) {
            while (isLowCaseLetter(s[i]) ||
                   isUpperCaseLetter(s[i]) ||
                   isDigital(s[i])) {
                buf += s[i];
                i++;
            }
            i -= 1;
            std::print("({},'{}') ", 10, buf);
            buf = {};
            continue;
        }
    }
    std::println("");
}

void ShowInfo() {
    std::string str = R"(
 * 2024/3/26
 * Compilation principle
 * Lexical Analyzer
 * Author: 甘劲博
 * StudentID: 2110551202
 * Class: 21计科5)";
    std::println("{}", str);
}

int main() {
    ShowInfo();

    std::string SourceCode{};
    std::println("Example: ");
    std::println("");
    SourceCode = "begin a:=9; x:=2 * 3; b:=a + x end #";
    std::println("{}", SourceCode);
    scanner(SourceCode);
    std::println("");
    SourceCode = "x:=a + b * c end #";
    std::println("{}", SourceCode);
    scanner(SourceCode);

    std::println("");
    std::println("Enter 'exit' to exit.");


    while (true) {
        std::println("Please enter the source code that needs to be processed:");
        std::getline(std::cin, SourceCode);
        if (SourceCode == "exit")
            return 0;
        std::println("{}", SourceCode);
        scanner(SourceCode);
    }
}
